#include "test02_MinExample.h"
#include <string>
#include <chrono>
#include <iostream>
#include <sstream>
#include <time.h>
//#include "json.hpp" // 提供json数据的序列化和反序列化工具

#pragma warning(disable:4996) // 可以忽略掉msvc认为不安全的一些操作

// 宏函数 = 相当于简单函数
// 平方
#define SQUARE(x) ((x) * (x))
#define PI 3.1416
// 圆的面积
#define AREA_CIRCLE(r) (PI*(r)*(r))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))



// 一些小例子
// 常用工具 = json解析，

void test02_MinExample::claMain()
{
	std::cout << "test02 \n";
	// 宏
	int n1 = 9;
	int n2 = 8;
	std::cout << "输入一个int整数: ";
	int num = 0;
	std::cin >> num;

	std::cout << "平方/SQUARE(" << num << ") = " << SQUARE(num) << std::endl;
	std::cout << "半径为 " << num << " 的圆的面积是: ";
	std::cout << AREA_CIRCLE(num) << std::endl;

	std::cout << "再输入一个int整数: ";
	int num2 = 0;
	std::cin >> num2;

	std::cout << "MIN(" << num << ", " << num2 << ") = ";
	std::cout << MIN(num, num2) << std::endl;

	std::cout << "MAX(" << num << ", " << num2 << ") = ";
	std::cout << MAX(num, num2) << std::endl;

	// json工具使用
	this->jsonTest("../config/config.json");

	// 过滤特殊符
	//std::cout << this->trim(" a b v"," \t\n\r") << std::endl;

	// 切分字符串
	//std::cout << "切分字符串 ";
	////this->split("ab c cd", " ", 2);
	//// 遍历容器
	//std::vector<std::string> valArray = this->split("ab c cd", " ", 2);
	////std::vector<std::string> words{ "I", "am", "the", "most", "handsome", "programmer" };
	//for (auto it = valArray.data(); it != valArray.data() + valArray.size(); it++)
	//{
	//	std::cout << *it << " ";
	//}

	// 输入输出
	this->fileAndOutHandle();

}

// json解析工具
void test02_MinExample::jsonTest(const std::string& file_path) { // 常量 string类型的地址 文件路径 即参数为string型的文件路径所指的地址
	std::cout << "解析json" << std::endl;
	//nlohmann::json  config(const std::string & file_path);
	//nlohmann::json json_config = config("./config.json");
	nlohmann::json json_config = test02_MinExample::config(file_path); // 解析json文件
	// 提取json项
	std::string broker_id = json_config["broker_id"].get<std::string>();
	std::cout << broker_id << std::endl;
}

// 过滤空格，\n,\t,\r = 只能过滤头，尾的，不能过滤中间的
std::string test02_MinExample::trim(const std::string& str,
	const char* charlist)
{
	int b = 0;
	int e = (int)str.size(); // 字符串长度
	std::cout << "====" << charlist << "-str-" << str[b] << std::endl;

	const char* result = std::strchr(charlist, str[b]); // 将查找结果存储在result指针中
	if (result != nullptr) { // 不为空指针
		std::cout << " 发现目标字符，位置为： " << (result - charlist) << std::endl;
	}
	else {
		//std::cout << "目标字符未发现" << std::endl;
	}

	while (b < e && strchr(charlist, str[b]) != NULL) // strchr-在一个串中查找给定字符的第一个位置，返回一个指针
	{ // 从 \n\t\r 中找传入的字符串第一次出现的位置
		// 从头向尾扫描，
		b++;
	}
	--e;
	while (e >= b && strchr(charlist, str[e]) != NULL)
	{
		--e;
	}
	++e;
	return str.substr(b, e - b);
}

// 解析json数据
nlohmann::json test02_MinExample::config(const std::string& file_path)
{
	std::fstream f; // 定义文件流对象
	// 异常处理
	try
	{
		f.open(file_path, std::ios::in); // 打开文件
		f.good();
	}
	catch (const std::exception& e)
	{
		// 文件打开异常
		std::cerr << "Exception caught: " << e.what() << '\n';
	}

	if (!f.is_open()) // 文件打开失败
	{
		f.close();
		std::cout << "Open file error!"
			<< " [file_path] " << file_path << std::endl;
		return nullptr;
	}

	auto json = nlohmann::json::parse(f); // 解析文本流为json格式

	f.close();

	if (true == json.is_null())
	{
		std::cout << "Parse json file error!" << std::endl;
	}
	return json;
}

// 按 分隔符切分字符串，切掉前面max_split段
std::vector<std::string> test02_MinExample::split(const std::string& str,
	const std::string& sep, int max_split)
{
	std::vector<std::string> res; // 字符串向量/动态数组，字符串转成字符数组
	std::string element;
	size_t i = 0; // size_t是个数据类型，为sizeof/size返回的类型
	while (i < str.size() && (max_split == -1 || (int)res.size() < max_split)) // 遍历字符串
	{
		if (str.substr(i, sep.size()) == sep) // 替换后与分隔符对比
		{
			res.push_back(element); // 向数组末尾添加一个元素
			element.clear();
			i += sep.size();
		}
		else
		{
			element += str[i];
			i++;
		}
	}
	element += str.substr(i);
	this->trim(element);
	res.push_back(element);
	std::cout << "element: " << element << std::endl;
	return res;
}

// 文件操作
// stream流 = “流”就是对外部设备使用的抽象，程序可以通过流写入外部设备，也可以从外部设备读入程序
// 一个C程序打开，就会打开三个默认的“流”
//		stdin —— 标准输入流（键盘）
//		stdout —— 标准输出流（屏幕）
//		stderr —— 标准错误流（屏幕）
// 在进行文件操作时，会用到文件指针，文件指针也是一个流——文件流
// fprintf sprintf 与fscanf sscanf进行逐一比较
// 输出流
//		fprintf作用：将格式化数据，输出到一个流中，一般是文件流或输出流
//		printf作用： 将格式化数据，输出到标准输出流（屏幕）中
// 输入流
//		scanf:作用于标准输入流（键盘）
//		fscanf：作用于所有流中
// sprintf和swprintf
// sscanf和swscanf
// 比较
//		printf——是针对标准输出流（stdout）的格式化输出函数
//		scanf——是针对标准输入流(stdin)的格式化输入函数
//		fpintf—— 是针对所有流的格式化输出函数
//		fscanf——是针对所有流的格式化输入函数
//		sprintf——将格式化数据转换为字符串
//		sscanf——将字符串数据转化为格式化数据

void test02_MinExample::fileAndOutHandle() {
	FILE* file = fopen("../config/output.txt", "w"); // 打开一个文件流用于写入

	if (file) {
		int num = 42;
		double pi = 3.14159;
		const char* str = "Hello, World!";

		// fprintf-格式化输出到一个流文件中
		fprintf(file, "The number is: %d\n", num); // 将格式化的整数写入文件
		fprintf(file, "The value of pi is: %f\n", pi); // 将格式化的浮点数写入文件
		fprintf(file, "A string: %s\n", str); // 将格式化的字符串写入文件


		fprintf(stdout, "The number is: %d\n", num); // stdout-标准输出流，打印到屏幕

		fclose(file); // 关闭文件流
	}
	else {
		std::cout << "文件打开失败\n";
		// 文件打开失败的处理代码
	}


}